//
// Created by 215609 on 2024/8/7.
//

#include "BaseDecoder.h"
int BaseDecoder::Init(const char *path,AVMediaType mediaType){
    strcpy(m_Url,path);
    m_MediaType=mediaType;
    return 0;
}

void BaseDecoder::UnInit(){
    if(m_Thread) {
        Stop();
        m_Thread->join();
        delete m_Thread;
        m_Thread = nullptr;
    }
}


void BaseDecoder::Stop(){
    m_DecoderState = STATE_STOP;
}

//void BaseDecoder::Pause(){
//
//}
//
//
//
//void BaseDecoder::Stop(){
//
//
//
//}
//
//
//
//
//
//void BaseDecoder::Start(){
//
//
//
//}
int BaseDecoder::InitFFDecoder() {
    int ret=-1;
    //1.创建封装格式上下文
    m_AVFormatContext=avformat_alloc_context();

    //2.打开文件
    if (avformat_open_input(&m_AVFormatContext,m_Url, nullptr, nullptr)!= 0){
        LOGCATE("avformat_open_input");
        return -1;
    }
    if (avformat_find_stream_info(m_AVFormatContext,nullptr)<0){
        LOGCATE("avformat_find_stream_info");
        return -1;
    }
//    m_AVFormatContext->streams[1]->time_base
    for (int i = 0; i < m_AVFormatContext->nb_streams; ++i){
        if (m_AVFormatContext->streams[i]->codecpar->codec_type==m_MediaType){
            m_StreamIndex = i;
            break;
        }
    }


    if (m_StreamIndex==-1){
        LOGCATE("avformat_find_stream_info %d",m_StreamIndex);
        return -1;
    }
    LOGCATE("avformat_find_stream_info success%d",m_StreamIndex);
    //5.获取解码器参数
    AVCodecParameters *codecParameters=m_AVFormatContext->streams[m_StreamIndex]->codecpar;
    //6.获取解码器
    m_AVCodec= avcodec_find_decoder(codecParameters->codec_id);
    if(m_AVCodec == nullptr) {
        LOGCATE("m_AVCodec");
        return -1;
    }

    m_AVCodecContext= avcodec_alloc_context3(m_AVCodec);

    if(avcodec_parameters_to_context(m_AVCodecContext,codecParameters)<0){
        LOGCATE("avcodec_parameters_to_context");
        return -1;
    }

    AVDictionary  *pAVDictionary=nullptr;
    av_dict_set(&pAVDictionary, "buffer_size", "1024000", 0);
    av_dict_set(&pAVDictionary, "stimeout", "20000000", 0);
    av_dict_set(&pAVDictionary, "max_delay", "30000000", 0);
    av_dict_set(&pAVDictionary, "rtsp_transport", "tcp", 0);


    //8.打开解码器
    ret= avcodec_open2(m_AVCodecContext,m_AVCodec,&pAVDictionary);
    if(ret < 0) {
        LOGCATE("avcodec_open2");
//        LOGCATE("DecoderBase::InitFFDecoder avcodec_open2 fail. result=%d", result);
        return -1;
    }
    ret = 0;
    m_Duration=m_AVFormatContext->duration/AV_TIME_BASE *1000;

     //创建 AVPacket 存放编码数据
    m_Packet = av_packet_alloc();

    m_Frame = av_frame_alloc();

    if(ret != 0 && m_MsgContext && m_MsgCallback)
        m_MsgCallback(m_MsgContext, MSG_DECODER_INIT_ERROR, 0);

    return ret;
}


void BaseDecoder::StartDecodingThread() {
     m_Thread=new thread(DoAVDecoding,this);


}

void BaseDecoder::UnInitDecoder() {
    if (m_Frame!=nullptr){
        av_frame_free(&m_Frame);
        m_Frame= nullptr;
    }

    if(m_Packet!=nullptr){
        av_packet_free(&m_Packet);
        m_Packet= nullptr;
    }

    if(m_AVCodecContext!=nullptr){
        avcodec_close(m_AVCodecContext);
        avcodec_free_context(&m_AVCodecContext);
        m_AVFormatContext= nullptr;
        m_AVCodec= nullptr;
    }

    if (m_AVFormatContext!=nullptr){
        avformat_close_input(&m_AVFormatContext);
        avformat_free_context(m_AVFormatContext);
        m_AVFormatContext = nullptr;
    }

}

void BaseDecoder::Start() {
    if (m_Thread==nullptr){
        StartDecodingThread();
    }else{
        unique_lock<std::mutex> lock(m_Mutex);
        m_DecoderState = STATE_DECODING;
        m_Cond.notify_all();
    }


}
int BaseDecoder::DecodeOnePacket() {
    LOGCATE("DecoderBase::DecodeOnePacket m_MediaType=%d", m_MediaType);
    if (m_SeekPosition >0){
        //seek to frame
        int64_t seek_target=static_cast<int64_t>(m_SeekPosition);
        int64_t seek_min = INT64_MIN;
        int64_t seek_max = INT64_MAX;
        int seek_ret=avformat_seek_file(m_AVFormatContext,-1,
                                        seek_min,seek_target,seek_max,0);
        if (seek_ret<0){
            m_SeekSuccess= false;
            LOGCATE("BaseDecoder::DecodeOneFrame error while seeking m_MediaType=%d", m_MediaType);

        }else{
            if (-1 !=m_StreamIndex){
                avcodec_flush_buffers(m_AVCodecContext);
            }
            ClearCache();
            m_SeekSuccess = true;
        }
    }  //进度条

    int ret= av_read_frame(m_AVFormatContext,m_Packet);
    while(ret==0){
        if (m_Packet->stream_index==m_StreamIndex){
            LOGCATE("m_StreamIndex %d",m_StreamIndex);
            if(avcodec_send_packet(m_AVCodecContext,m_Packet)==AVERROR_EOF){
                ret=-1;
                goto __EXIT;
            }
            int frameCount=0;
            while(avcodec_receive_frame(m_AVCodecContext, m_Frame)==0){
                //更新时间戳
                UpdateTimeStamp();
                AVSync();
                LOGCATE("DecoderBase::DecodeOnePacket 000 m_MediaType=%d", m_MediaType);
                OnFrameAvailable(m_Frame);
                LOGCATE("DecoderBase::DecodeOnePacket 0001 m_MediaType=%d", m_MediaType);

                ++frameCount;
            }
            LOGCATE("BaseDecoder::DecodeOneFrame frameCount=%d", frameCount);

            if (frameCount>0){
                ret = 0;
                goto __EXIT;
            }
        }
        av_packet_unref(m_Packet);
        ret= av_read_frame(m_AVFormatContext, m_Packet);

    }
        __EXIT:
        av_packet_unref(m_Packet);
        return ret;

}



void BaseDecoder::ClearCache() {



}

long BaseDecoder::AVSync() {


    //获取系统时间
    long curSysTime=GetSysCurrentTime();

    //基于系统时钟计算从开始播放流逝的时间
    long elapsedTime=curSysTime-m_StartTimeStamp;
    if(m_MsgContext && m_MsgCallback && m_MediaType == AVMEDIA_TYPE_AUDIO) {
     //时间回调
        m_MsgCallback(m_MsgContext, MSG_DECODING_TIME, m_CurTimeStamp * 1.0f / 1000);
    }

    long delay=0;

    //当前时间大于 播放的时间
    if (m_CurTimeStamp>elapsedTime){
        auto sleepTime=static_cast<unsigned int>(m_CurTimeStamp -elapsedTime );
        sleepTime = sleepTime > DELAY_THRESHOLD ? DELAY_THRESHOLD :  sleepTime;
        av_usleep(sleepTime * 1000);
    }
    delay = elapsedTime - m_CurTimeStamp;
    return delay;
}


void BaseDecoder::UpdateTimeStamp() {
     unique_lock<mutex> lock(m_Mutex);
///AVPacket的dts拷贝为AVFrame的pkt_dts, AVPacket的pts拷贝为AVFrame的pkt_pts。
    if (m_Frame->pkt_dts!=AV_NOPTS_VALUE){
        m_CurTimeStamp=m_Frame->pkt_dts;
        LOGCATE("DecoderBase::UpdateTimeStamp pkt_dts %ld %f",m_CurTimeStamp);
    }else if (m_Frame->pts!=AV_NOPTS_VALUE){
        m_CurTimeStamp=m_Frame->pts;
        LOGCATE("DecoderBase::UpdateTimeStamp pts %ld %f",m_CurTimeStamp);
    }else{
        LOGCATE("DecoderBase::UpdateTimeStamp m_CurTimeStamp=0 %ld %f",m_CurTimeStamp);
        m_CurTimeStamp=0;
    }

    m_CurTimeStamp=(int64_t)((m_CurTimeStamp * av_q2d(m_AVFormatContext->streams[m_StreamIndex]->time_base)) * 1000);

    if (m_SeekPosition>0 && m_SeekSuccess){
        m_StartTimeStamp=GetSysCurrentTime()-m_CurTimeStamp;
        m_SeekPosition = 0;
        m_SeekSuccess= false;
    }
}

void BaseDecoder::DecodingLoop() {
    {
        unique_lock<mutex> lock(m_Mutex);
        m_DecoderState = STATE_DECODING;
        lock.unlock();
    }

    for (; ;) {
        while(m_DecoderState==STATE_PAUSE){
            unique_lock<mutex> lock(m_Mutex);
            m_Cond.wait_for(lock,chrono::milliseconds(10));
            m_StartTimeStamp = GetSysCurrentTime() - m_CurTimeStamp;
        }

        if (m_DecoderState==STATE_STOP){
            break;
        }

        if (m_StartTimeStamp==-1){
            m_StartTimeStamp=GetSysCurrentTime();
        }

        if (DecodeOnePacket()!=0){
            //解码结束，暂停解码器
            unique_lock<mutex> lock(m_Mutex);
            m_DecoderState=STATE_PAUSE;
        }
    }
}

void BaseDecoder::DoAVDecoding(BaseDecoder *decoder) {
    LOGCATE("AVPlayer_play1122");
    if (decoder->InitFFDecoder() != 0){
        return ;
    }
    decoder->OnDecoderReady();
    LOGCATE("AVPlayer_play112244");
    decoder->DecodeOnePacket();
    LOGCATE("AVPlayer_play112244444");
    decoder->DecodingLoop();
    LOGCATE("AVPlayer_play1122444444343");
    decoder->UnInitDecoder();

    decoder->OnDecoderDone();

}




